[LeetCode]买卖股票合集
简单整理一下LeetCode上买卖股票
系列题目. 包含买卖股票的最佳时机
、买卖股票的最佳时机 II
、买卖股票的最佳时机 III
、买卖股票的最佳时机 IV
、最佳买卖股票时机含冷冻期
和买卖股票的最佳时机含手续费
共六题.
买卖股票的最佳时机
题目描述
给出数组price
, 其中price[i]
表示第i
天股票的价格. 只能选择某一天买入然后之后的某一天卖出, 求最大利润.
思路
- 贪心. 如果在第
i
天卖出, 那么一定希望买入的时候价格最低, 因此使用维护一个前缀最小值即可. - 状态机动态规划
- 状态机关心的时当前处于何种
状态
, 以及所有可能的状态转移和条件 - 动态规划
- 状态定义
f[i][0][0]
: 表示第i
天没持有股票, 且没完成一次交易的最大利润(一定为0).f[i][1][0]
: 表示第i
天持有股票, 且没完成一次交易的最大利润.f[i][0][1]
: 表示第i
天没持有股票, 且完成一次交易的最大利润.f[i][1][1]
: 表示第i
天持有股票, 且完成一次交易的最大利润.
- 状态转移
- $f[i][0][0] = f[i - 1][0][0] = 0$
- $f[i][1][0] = max(f[i - 1][1][0], -price[i])$, 表示要么是第
i - 1
天持有, 要么是第i
天买入. - $f[i][0][1] = max(f[i - 1][0][1], f[i - 1][1][0] + price[i])$, 表示要么是第
i - 1
天完成一次交易, 要么是第i
天卖出后完成了一次交易. - $f[i][1][1] = max(f[i - 1][1][1], f[i - 1][0][1] - price[i])$, 表示要么是第
i - 1
天持有, 要么是第i
天买入.
- 状态定义
- 使用三维的原因是必须保证只能完成一次交易, 因此需要对状态进行拆分.
- 状态的表示是持有股票或不持有股票, 而买入卖出是动作, 是状态转移的条件.
- 状态初始化中, 由于第一天无法完成一次交易, 因此$f[1][0][1]=f[1][1][1]=-INF$.
- 由于$f[i][1][1]$无法转移到其他任何状态, 而且其也不会是答案, 因此其为无效状态, 无需计算.
- 状态机关心的时当前处于何种
Code
1 | /* |
1 | // 状态机动态规划 |
复杂度分析(状态机动态规划)
- 时间复杂度$O(N)$
- 空间复杂度$O(N)$
买卖股票的最佳时机 II
题目描述
基本题意与第一题相同, 只是多了个条件: 可以完成任意交易.
思路
- 本题无需关注交易次数, 只需关注在每个时间点所处的状态以及所有可能的转移及条件, 因此简单修改第一题状态机动态规划做法即可.
- 状态机动态规划
- 状态定义:
f[i][0]
: 表示第i
天没持有股票时候的最大收益f[i][1]
: 表示第i
天持有股票时候的最大收益
- 状态转移:
- $f[i][0] = max(f[i - 1][0], f[i - 1][1] + price[i])$, 表示第
i
天不持有可以从第i - 1
天不持有或者第i - 1
天持有但第i
天卖掉转移而来. - $f[i][1] = max(f[i - 1][1], f[i - 1][0] - price[i])$, 表示第
i
天持有可以从第i - 1
天持有或者第i - 1
天不持有但第i
天买入转移而来.
- $f[i][0] = max(f[i - 1][0], f[i - 1][1] + price[i])$, 表示第
- 状态定义:
- 最终答案:
f[n][0]
Code
1 | class Solution { |
复杂度分析
- 时间复杂度$O(N)$
- 空间复杂度$O(N)$
买卖股票的最佳时机 III
题目描述
基本题意与第一题相同, 只是多了个条件: 最多完成两笔交易.
思路
- 第一题解法中使用三维状态来标记完成交易的次数, 本题只是第一题的简单扩展, 在第一题基础上稍加修改即可.
- 状态机动态规划
- 状态定义:
- $f[i][0][0]$: 表示第
i
天不持有股票, 且完成0
笔交易时的最大收益(一定为0, 无效状态) - $f[i][1][0]$: 表示第
i
天持有股票, 且完成0
笔交易时的最大收益 - $f[i][0][1]$: 表示第
i
天不持有股票, 且完成1
笔交易时的最大收益 - $f[i][0][2]$: 表示第
i
天不持有股票, 且完成2
笔交易时的最大收益 - $f[i][1][1]$: 表示第
i
天持有股票, 且完成1
笔交易时的最大收益 - $f[i][1][2]$: 表示第
i
天持有股票, 且完成2
笔交易时的最大收益(无效状态)
- $f[i][0][0]$: 表示第
- 状态转移:
- $f[i][1][0] = max(f[i - 1][1][0], f[i - 1][0][0] - p[i])$, 表示第
i
天持有可以从第i - 1
天持有或者第i - 1
天不持有但第i
天买入转移而来. - $f[i][0][1] = max(f[i - 1][0][1], f[i - 1][1][0] + p[i])$, 转移同上, 要么前一天同状态转移过来, 要么前一天某状态通过买入/卖出转移过来.
- $f[i][0][2] = max(f[i - 1][0][2], f[i - 1][1][1] + p[i])$
- $f[i][1][1] = max(f[i - 1][1][1], f[i - 1][0][1] - p[i])$
- $f[i][1][0] = max(f[i - 1][1][0], f[i - 1][0][0] - p[i])$, 表示第
- 由于第一天无法完成交易, 因此需要初始化第一天的某些状态为非法状态.
- 状态定义:
Code
1 | const int N = 1e5 + 5; |
复杂度分析
- 时间复杂度$O(N)$
- 空间复杂度$O(N)$
买卖股票的最佳时机 IV
题目描述
基本题意与第一题相同, 只是多了个条件: 最多完成k
笔交易.
思路
- 第一题状态机动态规划解法与第三题的推广版本, 完全一致的思路, 照抄即可.
- 状态机动态规划
- 状态定义:
- $f[i][0][j]$: 表示第
i
天不持有股票, 且完成j
笔交易时的最大收益 - $f[i][1][j]$: 表示第
i
天持有股票, 且完成j
笔交易时的最大收益
- $f[i][0][j]$: 表示第
- 状态转移:
- $f[i][0][j] = max(f[i - 1][0][j], f[i - 1][1][j - 1] + p[i])$
- $f[i][1][j] = max(f[i - 1][1][j], f[i - 1][0][j] - p[i])$
- 状态定义:
Code
1 | const int N = 1010, K = 110; |
复杂度分析
- 时间复杂度$O(N * K)$
- 空间复杂度$O(N * K)$
最佳买卖股票时机含冷冻期
题目描述
基本题意与第一题相同, 只是多了条件: 可以买卖任意次, 但卖出股票后,无法在第二天买入股票 (即冷冻期为 1 天)。
思路
- 基本为第二题的扩展. 考虑如何将冷冻期为 1 天用状态表达出来即可.
- 状态机动态规划
- 状态定义:
- $f[i][0]$: 表示第
i
天不持有股票, 且无冷冻期, 时候的最大收益. - $f[i][1]$: 表示第
i
天不持有股票, 且在冷冻期(第i - 1天卖出), 时候的最大收益. - $f[i][2]$: 表示第
i
天持有股票时候的最大收益
- $f[i][0]$: 表示第
- 状态转移:
- $f[i][0] = max(f[i - 1][0], f[i - 1][1])$
- $f[i][1] = f[i - 1][2] + p[i]$
- $f[i][2] = max(f[i - 1][2], f[i - 1][0] - p[i])$
- 状态定义:
Code
1 | class Solution { |
复杂度分析
- 时间复杂度$O(N)$
- 空间复杂度$O(N)$
买卖股票的最佳时机含手续费
题目描述
基本题意与第一题相同, 只是多了条件: 可以买卖任意次, 且一次买入卖出需要支付手续费。
思路
- 第二题的简单扩展. 卖出阶段支付手续费即可.
- 状态机动态规划
- 状态定义:
- $f[i][0]$: 表示第
i
天不持有股票时候的最大收益. - $f[i][1]$: 表示第
i
天持有股票时候的最大收益.
- $f[i][0]$: 表示第
- 状态转移:
- $f[i][0] = max(f[i - 1][0], f[i - 1][1] + p[i] - fee)$
- $f[i][1] = max(f[i - 1][1], f[i - 1][0] - p[i])$
- 状态定义:
Code
1 | const int N = 1e5 + 5; |
复杂度分析
- 时间复杂度$O(N)$
- 空间复杂度$O(N)$
参考资料
欢迎讨论指正